package org.yenbay.timer;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 


/**
 * Created by yenbay at 2020-12-27 14:32:57 <br> 命令行参数args解析器，解析为map
 *
 */  
public class ArgumentParser implements Serializable {

	private static final long serialVersionUID = 1L;

	private static final Pattern MIDLINE_Abcd_PATTERN = Pattern.compile("^-{1,2}([A-Z])([a-z\\d\\.@_\\-\\\\/]+)$");
	private static final Pattern MIDLINE_A_OR_a_PATTERN = Pattern.compile("^-{1,2}([A-Za-z])$");
	private static final Pattern MIDDLE_aBcD_PATTERN = Pattern.compile("^-{1,2}([a-z][a-zA-Z\\d\\.@\\-_\\\\/]+)$");
	private static final Pattern EQUAL_PATTERN = Pattern.compile("^(?:-{1,2})?([a-zA-Z\\d\\.\\-_]+)=([\\*a-zA-Z:\\d\\.@\\-_\\\\/\\u4e00-\\u9fa5\\u3002\\uff1f\\uff01\\uff0c\\u3001\\uff1b\\uff1a\\u201c\\u201d\\u2018\\u2019\\uff08\\uff09\\u300a\\u300b\\u3008\\u3009\\u3010\\u3011\\u300e\\u300f\\u300c\\u300d\\ufe43\\ufe44\\u3014\\u3015\\u2026\\u2014\\uff5e\\ufe4f\\uffe5,]*)$");
	private static final Pattern STRING_ONLY_PATTERN = Pattern.compile("^[a-zA-Z\\d\\.@\\-_\\\\/]+$");
	private static final Pattern COMPLEX_EQUAL_PATTERN = Pattern.compile("^(?:-{1,2})?([a-zA-Z\\d\\.\\-_]+)=(?:\"([^\"]*)\"|'([^']*)')$");
 
	private final String[] args; 
	private final Map<String, String> map = new LinkedHashMap<>(30);
	 
	public ArgumentParser(String[] args) {
		this.args = args;
	}

	/**
	 * 构建参数解析对象实例
	 * 
	 * @param args 参数值
	 * @return
	 */
	public static ArgumentParser build(String[] args) { 
		ArgumentParser parser = new ArgumentParser(args);
		parser.parse(); 
		return parser;
	}

	/**
	 * 返回还原的命令参数字符串值
	 * 
	 * @return
	 */
	public String origin() {
		StringBuffer sb = new StringBuffer(); 
		if(args != null) {
			for(String s : args) {
				sb.append(s);
				sb.append(" ");
			}
		}
		if(sb.length() > 0) {
			sb.setLength(sb.length() - 1);
		}
		return sb.toString();
	}

	/**
	 * 判断某个参数名是否存在
	 * 
	 * @see map.containsKey(name)
	 * 
	 * @param name 参数名
	 * @return
	 */
	public boolean exists( String name) {
		return map.containsKey(name);
	} 
	
	/**
	 * 判断某个参数名对应的value值不为空白
	 * 
	 * @see map.get(name) != null && map.get(name).toString().trim().length() > 0
	 * 
	 * @param name
	 * @return
	 */
	public boolean existsValue(String name) {
		String value = map.get(name);
		return value != null && value.trim().length() > 0;
	}
	
	/**
	 * 遍历参数
	 * 
	 * @param consumer 遍历参数的回调
	 */
	public void each(Consumer<NameValue> consumer) {
		map.entrySet().stream().forEachOrdered(entry -> {
			consumer.accept(new NameValue().setName(entry.getKey()).setValue(entry.getValue()));
		});
	}

	/**
	 * 获取值，如果值为空白，则返回给定的默认值
	 * 
	 * @param name 参数名
	 * @param defaultValue 默认参数取值
	 * @return
	 */
	private String getString(String name, String defaultValue) {
		String value = map.get(name);
		if(value == null) {
			return defaultValue;
		}
		if(value.trim().length() == 0) {
			return defaultValue;
		} 
		return value; 
	}

	/**
	 * 获取非空白值
	 * 
	 * @param name 参数名
	 * @return
	 */
	public String get( String name) {
		return getString(name, null);
	}

	/**
	 * 获取值，如果值为空白，则返回给定的默认值
	 * 
	 * @param name 参数名
	 * @param defaultValue 默认参数取值
	 * @return
	 */
	public String get( String name, Object defaultValue) {
		return getString(name, defaultValue == null ? null : defaultValue.toString());
	}

	/**
	 * 获取值，如果值为空白，则返回给定的默认值，否则转换为指定类型值
	 * 
	 * @param <T>
	 * @param name 参数名
	 * @param defaultValue 默认参数取值
	 * @param clazz 参数值类型
	 * @return
	 */ 
	public  <T> T get( String name, T defaultValue,  Class<T> clazz) { 
		String stringValue = get(name, null); 
		if(stringValue == null) {
			return defaultValue;
		}
		return castType(stringValue, clazz);
	}

	/**
	 * 依次根据name获取参数值，直到获取到非空的参数值，常用于同时支持多个参数名的方式，例如 -v,--version
	 * 
	 * @param names 给定多个参数名，按顺序查找
	 * @return
	 */
	public String getUntil( String... names) {
		for(String name : names) {
			String val = get(name);
			if(val != null) {
				return val;
			} 
		}
		return null;
	}

	/**
	 * 获取非null参数值，如果获取的参数值为空白，则返回给定的非null的默认值
	 * 
	 * @param <T>
	 * @param name 参数名
	 * @param defaultValue 默认参数取值，非null
	 * @return
	 */
	public <T> T getNonNull( String name, T defaultValue) {
		@SuppressWarnings("unchecked")
		Class<T> clazz = (Class<T>) defaultValue.getClass();
		return get(name, defaultValue, clazz);
	}
	
	/**
	 * 获取特殊Boolean开关量，如果是--key=true/false情形，则取值为对应的值，否则当键存在时为true,不存在为false
	 * <br>
	 * 例如： --key=true 参数key取值为true, --key=false 参数key取值为false, --key 参数key取值为true，--key=xyz任意其他值 参数key取值为true, 当没有key参数时，取值为false
	 * 
	 * @param name
	 * @return
	 */
	public boolean getComplexBool(String name) {
		if(!map.containsKey(name)) {
			return false;
		}
		String stringValue = map.get(name);
		if("true".equalsIgnoreCase(stringValue)) {
			return true;
		}
		if("false".equalsIgnoreCase(stringValue)) {
			return false;
		} 
		return true;
	}


	@SuppressWarnings("unchecked")
	private <T> T castType(String stringValue, Class<T> clazz) {
		// String
		if(clazz.equals(String.class)) {
			return (T) stringValue;
		}
		// Boolean
		if(clazz.equals(Boolean.class)) { 
			if("true".equalsIgnoreCase(stringValue)) {
				return (T) Boolean.TRUE;
			}
			if("false".equalsIgnoreCase(stringValue)) {
				return (T) Boolean.FALSE;
			}
			throw new IllegalArgumentException("Invalid boolean value: " + stringValue);
		}
		// Long
		if(clazz.equals(Long.class)) {
			return (T) Long.valueOf(stringValue);
		}
		// Integer
		if(clazz.equals(Integer.class)) {
			return (T) Integer.valueOf(stringValue);
		}
		// Double
		if(clazz.equals(Double.class)) { 
			return (T) Double.valueOf(new BigDecimal(stringValue).doubleValue());
		}
		// Float
		if(clazz.equals(Float.class)) { 
			return (T) Float.valueOf(new BigDecimal(stringValue).floatValue());
		}
		// BigDecimal
		if(clazz.equals(BigDecimal.class)) { 
			return (T) new BigDecimal(stringValue);
		}
		// Byte
		if(clazz.equals(Byte.class)) { 
			return (T) Byte.valueOf(new BigDecimal(stringValue).byteValue());
		}
		// Character
		if(clazz.equals(Character.class)) { 
			// 取第一个字符
			return (T) Character.valueOf(stringValue.charAt(0));
		}
		// Short
		if(clazz.equals(Short.class)) { 
			return (T) Short.valueOf(new BigDecimal(stringValue).shortValue());
		} 
		throw new IllegalArgumentException("Unsupported value class: " + clazz.getName());
	}

	@Override
	public String toString() {
		StringBuffer buf = new StringBuffer();
		each(e -> {
			buf.append(e.getName());
			buf.append("=");
			buf.append(e.getValue());
			buf.append(",");
		});
		if(buf.length() > 0) {
			buf.setLength(buf.length() - 1);
		}
		return buf.toString();
	}

	/**
	 * 构建参数Map
	 */
	private void parse() {
		if(this.args == null) {
			return;
		}
		if(this.args.length == 0) {
			return;
		} 
		Arrays.stream(this.args)
		.filter(arg -> arg != null && arg.trim().length() > 0)
		.forEachOrdered(arg -> { 
			arg = arg.trim();
			Matcher m = null;
			if(arg.contains("=")) {
				// --abc=xxx型	或者	-abc=xxx型	 或者	abc=xxx型
				m = EQUAL_PATTERN.matcher(arg);
				if(m.find()) {
					map.put(m.group(1), m.group(2));
					return;
				}
				// --abc="xxx"型	或者	-abc="xxx"型	 或者	abc="xxx"型  或者 --abc='xxx'型	或者	-abc='xxx'型	 或者	abc='xxx'型
				m = COMPLEX_EQUAL_PATTERN.matcher(arg);
				if(m.find()) {
					String val = m.group(2);
					if(val == null) {
						val = m.group(3);
					}
					map.put(m.group(1), val);
					return;
				}
				System.out.println("[WARN] Illegal parameter argument: " + arg);
				return;
			}
			//
			if(arg.startsWith("-")) {
				// -Pabc型    或者   --Pabc
				m = MIDLINE_Abcd_PATTERN.matcher(arg);
				if(m.find()) {
					map.put(m.group(1), m.group(2));
					return;
				}
				// -P型	 或者	-p型	或者	--P	或者	--p
				m = MIDLINE_A_OR_a_PATTERN.matcher(arg);
				if(m.find()) {
					map.put(m.group(1), m.group(1));
					return;
				}
				// -aXXX型或者--aXXX
				m = MIDDLE_aBcD_PATTERN.matcher(arg);
				if(m.find()) {
					map.put(m.group(1), m.group(1));
					return;
				}
				System.out.println("[WARN] Illegal parameter argument: " + arg);
				return;
			}
			//
			// abcd型
			m = STRING_ONLY_PATTERN.matcher(arg);  
			if(m.find()) {
				map.put(m.group(0), m.group(0));
				return;
			} 
			System.out.println("[WARN] Illegal parameter argument: " + arg);
			return; 
		});  
	}

	/**
	 * Created by yenbay at 2020-12-27 14:37:19 <br> 参数键值对
	 *
	 */ 
	public static final class NameValue implements Serializable{ 
		private static final long serialVersionUID = 1L;
		
		private String name;
		private String value;
		
		public String getName() {
			return name;
		}
		public NameValue setName(String name) {
			this.name = name;
			return this;
		}
		public String getValue() {
			return value;
		}
		public NameValue setValue(String value) {
			this.value = value;
			return this;
		} 
	}

	public static void main(String[] args) {
		args = new String[] {"--help","-Dfile.encoding=UTF-8","-Ptest","--p=false","-ss=\"fs sf\"","test","-Sdes.df_test","-Pds.dsd=sdf_ddd","-dfsf=/user/tt.file"};
		ArgumentParser parser = ArgumentParser.build(args);
		System.out.println(parser.origin());
		parser.each(nv -> { 
			System.out.println(nv.getName() + "=" + nv.getValue()); 
		});
		// {help=help, start=start, P=test, psfff=psfff, ss=fssf, test=test, S=des.df_test, Pds.dsd=sdf_ddd, dfsf=/user/tt.file}
	}
}
